
import type { RouteRecordRaw, RouteMeta, RouteRecordName, RouteLocationNormalizedLoaded, RouteRecordNormalized } from 'vue-router';
import { filterRecursively, forEachRecursively, reduceRecursively, mapRecursively } from '@/utils/array-recursion'

export type MenuItemType = 'Directory' | 'Page' | 'ExternalLink'

export type RouteMetaMore = RouteMeta & {
    title?: string
    type?: MenuItemType
    icon?: string
    url?: string
    permission?: string
    componentPath?: string
    menuGroup?: string
    hidden?: boolean
    affix?: boolean
    noCache?: boolean
}

type Optional<T,K extends keyof T, O extends keyof T> = Pick<T,K> & Partial<Pick<T,O>>

export interface RouteView extends Optional<RouteLocationNormalizedLoaded, 'path' | 'name' ,'matched' | 'params' | 'query' | 'hash' | 'redirectedFrom'> {
    fullPath: string
    meta: RouteMetaMore
}



export type MenuItem = {
    path: string
    title?: string
    url?: string
    fullUrl?: string
    groupCode?: string
    icon?: string
    type?: MenuItemType
    name?: RouteRecordName
    pagePath?: string
    permission?: string
    meta?: RouteMeta
    children?: MenuItem[]
    level?: number
    affix?: boolean
    hidden?: boolean
    parentId?: number
    sequence?: number
}


export function convertRouteLocationToRouteView(route: RouteLocationNormalizedLoaded): RouteView {
    const { meta } = route;
    meta.url =
      route.path +
      `?${route.meta.appName}=` +
      encodeURIComponent("/#" + route.meta.childAppPath);
    return { ...route, meta };
}


export function convertRouteRecordToRouteView(route: RouteRecordNormalized): RouteView {
    return { ...route, fullPath: route.path};
}

export function buildMenuFromRoutes(routes: RouteRecordRaw[]): MenuItem[] {
    const menuItems = mapRecursively<RouteRecordRaw, MenuItem>([...routes], (currentRoute) => {
        const meta = currentRoute.meta as RouteMetaMore | undefined
        const menuItem: MenuItem = {
            path: currentRoute.path,
            name: currentRoute.name || meta?.title,
            meta: meta,
            url: meta?.url,
            title: meta?.title,
            type: meta?.type,
            icon: meta?.icon,
            affix: meta?.affix,
            hidden: meta?.hidden,
            pagePath: meta?.componentPath,
            permission: meta?.permission,
            children: currentRoute.children
        };

        return menuItem
    })

    return mapRecursively(menuItems, (menuItem) => {
        if (Array.isArray(menuItem.children) && menuItem.children.length == 1) {
            const childMenuItem: MenuItem = menuItem.children[0]
            childMenuItem.path = (menuItem.path + '/' + childMenuItem.path).replaceAll("//", "/")
            return childMenuItem
        } else {
            return menuItem
        }
    }, undefined, true).reduce((menu, rootMenuItem) => {
        if (rootMenuItem.path == '/') {
            if (Array.isArray(rootMenuItem.children) && rootMenuItem.children.length > 0) {
                rootMenuItem.children.forEach(_menuItem => {
                    if (Array.isArray(_menuItem.children)) {
                        menu.push(..._menuItem.children)
                    }
                })
            } else {
                menu.push(rootMenuItem)
            }
        } else {
            menu.push(rootMenuItem)
        }
        return menu
    }, [] as MenuItem[])
}


export function hasPermission(route: RouteRecordRaw, permissions: Array<string>): boolean {
    const meta = route.meta as (RouteMetaMore | undefined)
    const permission = meta?.permission;
    if (permission) {
        const permissionParts = permission.split(":");
        return typeof permissions.find((_permission) => {
            const _permissionParts = _permission.split(":");
            const min = Math.min(permissionParts.length, _permissionParts.length);
            for (let i = 0; i < min; i++) {
                const _permissionPart = _permissionParts[i];
                const permissionPart = permissionParts[i];
                if ("*" === _permissionPart) {
                    //当前段匹配
                } else if ("**" === _permissionPart) {
                    //全部匹配
                    return true;
                } else if (_permissionPart != permissionPart) {
                    //当前段不匹配，整体不匹配
                    return false;
                }
            }
            return permissionParts.length <= _permissionParts.length;
        }) != 'undefined';
    } else {
        return true
    }
}



/**
 * 对从api接口查询得到的菜单项数组进行格式化
 * @param menuItems 
 * @param upgradeSingle 
 */
export function formattingMenuItems(menuItems: MenuItem[], upgradeSingle: boolean | undefined = true): void {

    const initialResult: { levels: number } = { levels: 0 }

    const result = reduceRecursively(menuItems, (result, menuItem, index, arr, parentItem) => {
        menuItem.level = result.levels
        if (parentItem) {
            result.levels = parentItem.level! + 1
        }
        return result
    },
        initialResult)

    if (result.levels > 1) {
        menuItems.forEach(menuItem => {
            if (Array.isArray(menuItem.children)) {
                formattingMenuItems(menuItem.children, upgradeSingle)
            }
        })
    }


    for (let i = menuItems.length - 1; i >= 0; i--) {
        const menuItem = menuItems.at(i);
        if (Array.isArray(menuItem!.children) && (menuItem!.path == "/" || (upgradeSingle ? menuItem!.children.length == 1 : false))) {
            const args: [start: number, deleteCount: number, ...items: MenuItem[]] = [i, 1, ...menuItem!.children];
            menuItems.splice(...args)
        } else {
            menuItem!.level = undefined
        }
    }
}


export function filterMenuItems() {

}

/**
 * 用过滤好的菜单项数组构建本地菜单
 * @param menuItems 
 * @returns 
 */
export function buildMenu(menuItems: MenuItem[]): MenuItem[] {
    const filteredMenu =  filterRecursively(menuItems, (menuItem) => {
        if (menuItem.hidden) {
            return false
        } else if (menuItem.type == 'Directory') {
            return Array.isArray(menuItem.children) && menuItem.children.length > 0
        } else if (menuItem.path) {
            const pathParts = menuItem.path.split('/')
            return typeof (pathParts.find(pathPart => pathPart.indexOf(':') === 0)) == 'undefined'
        } else {
            return false
        }
    },
        undefined,
        true,
    )



    //合并多个菜单组
    const finalMenu: MenuItem[] = []
    filteredMenu.forEach(menuItem => {
        if (Array.isArray(menuItem.children)) {
            const existItem = finalMenu.find(_item => _item.path == menuItem.path)
            if (existItem) {
                existItem.children = existItem.children!.concat(menuItem.children)
            } else {
                finalMenu.push(menuItem)
            }
        } else {
            finalMenu.push(menuItem)
        }
    })

    forEachRecursively(finalMenu, (menuItem, index, arr, parentItem) => {
        if (menuItem.type == 'Page') {
            menuItem.fullUrl = menuItem.url + `?${menuItem.groupCode}=` + encodeURIComponent('/#' + menuItem.url)
        } else if (Array.isArray(menuItem.children)) {
            menuItem.children.sort((item1, item2) => {
                return (item1.sequence || 0) - (item2.sequence || 0)
            })
        }
    })


    return finalMenu
}


function convertMenuItemsToRoutes(menuItems: MenuItem[]): RouteRecordRaw[] {
    // const modules = import.meta.glob('@/views/**/*.vue')

    function convert(_routes: RouteRecordRaw[], menuItem: MenuItem): RouteRecordRaw[] {
        if (menuItem.type == "Directory") {
            if (Array.isArray(menuItem.children)) {
                return menuItem.children.reduce(convert, _routes);
            } else {
                return _routes
            }
        } else {
            if (menuItem.type == "Page") {
                const _component = menuItem.groupCode == 'local' ? () => import("@/views/micro-app/child-app-vite.vue") : () => import("@/views/micro-app/child-app-vue2.vue")
                const appName = menuItem.groupCode
                const routeName = (menuItem.groupCode || '') + ((menuItem.name as string) || menuItem.path)

                const meta: RouteMetaMore = {
                    title: menuItem.title,
                    url: menuItem.url,
                    icon: menuItem.icon,
                    menuGroup: menuItem.groupCode,
                    componentPath: menuItem.pagePath,
                    type: menuItem.type,
                    permission: menuItem.permission,
                }

                const route: RouteRecordRaw = {
                    path: menuItem.url!.substring(1),
                    name: routeName,
                    component: _component,
                    meta: meta,
                    children: []
                };




                if (menuItem.affix) {
                    route.meta!.affix = true
                }

                route.props = { name: appName, path: menuItem.url, groupCode: menuItem.groupCode }
                if (!route.meta) {
                    route.meta = {}
                }
                route.meta.childAppPath = menuItem.url
                route.meta.appName = appName

                _routes.push(route)
            }

            return _routes;
        }

    }



    const routes = [{
        path: '/',
        name: "Layout",
        meta: {
            type: 'Directory',
        },
        component: () => import('@/layout/LayoutPage.vue'),
        children: menuItems.reduce(convert, [])
    }] as RouteRecordRaw[]



    forEachRecursively(routes, (route) => {
        if (Array.isArray(route.children) && route.children.length > 0) {
            route.redirect = (route.children[0].meta!.url as string)
        }
    })
    return routes;
}

/**
 * 用过滤好的菜单项数组构建本地路由
 * @param menuItems 
 */
export function buildRoutesWithMenuItems(menuItems: MenuItem[]) {
    const filteredMenuItems = filterRecursively(menuItems, (menuItem) => {
        return menuItem.type != 'ExternalLink'
    })
    return convertMenuItemsToRoutes(filteredMenuItems)
}









